home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 051-075 / 074 / less / screen.c < prev    next >
C/C++ Source or Header  |  1995-03-13  |  11KB  |  536 lines

  1. /*
  2.  * Routines which deal with the characteristics of the terminal.
  3.  * Uses termcap to be as terminal-independent as possible.
  4.  *
  5.  * {{ Someday this should be rewritten to use curses. }}
  6.  */
  7.  
  8. #include "less.h"
  9. #if XENIX
  10. #include <sys/types.h>
  11. #include <sys/ioctl.h>
  12. #endif
  13.  
  14. #if TERMIO
  15. #include <termio.h>
  16. #else
  17. # ifndef amiga
  18. # include <sgtty.h>
  19. # endif
  20. #endif
  21.  
  22. /*
  23.  * Strings passed to tputs() to do various terminal functions.
  24.  */
  25. static char
  26.     *sc_pad,                /* Pad string */
  27.     *sc_home,               /* Cursor home */
  28.     *sc_addline,            /* Add line, scroll down following lines */
  29.     *sc_lower_left,         /* Cursor to last line, first column */
  30.     *sc_move,               /* General cursor positioning */
  31.     *sc_clear,              /* Clear screen */
  32.     *sc_eol_clear,          /* Clear to end of line */
  33.     *sc_s_in,               /* Enter standout (highlighted) mode */
  34.     *sc_s_out,              /* Exit standout mode */
  35.     *sc_u_in,               /* Enter underline mode */
  36.     *sc_u_out,              /* Exit underline mode */
  37.     *sc_visual_bell,        /* Visual bell (flash screen) sequence */
  38.     *sc_backspace,          /* Backspace cursor */
  39.     *sc_init,               /* Startup terminal initialization */
  40.     *sc_deinit;             /* Exit terminal de-intialization */
  41. static int dumb;
  42. static int hard;
  43.  
  44. public int auto_wrap;           /* Terminal does \r\n when write past margin */
  45. public int ignaw;               /* Terminal ignores \n immediately after wrap */
  46. public int erase_char, kill_char; /* The user's erase and line-kill chars */
  47. public int sc_width, sc_height; /* Height & width of screen */
  48. public int ul_width, ue_width;  /* Printing width of underline sequences */
  49. public int so_width, se_width;  /* Printing width of standout sequences */
  50.  
  51. /*
  52.  * These two variables are sometimes defined in,
  53.  * and needed by, the termcap library.
  54.  * It may be necessary on some systems to declare them extern here.
  55.  */
  56. /*extern*/ short ospeed;        /* Terminal output baud rate */
  57. /*extern*/ char PC;             /* Pad character */
  58.  
  59. extern int quiet;               /* If VERY_QUIET, use visual bell for bell */
  60. extern int know_dumb;           /* Don't complain about a dumb terminal */
  61. extern int back_scroll;
  62. char *tgetstr();
  63. char *tgoto();
  64.  
  65. /*
  66.  * Change terminal to "raw mode", or restore to "normal" mode.
  67.  * "Raw mode" means 
  68.  *      1. An outstanding read will complete on receipt of a single keystroke.
  69.  *      2. Input is not echoed.  
  70.  *      3. On output, \n is mapped to \r\n.
  71.  *      4. \t is NOT be expanded into spaces.
  72.  *      5. Signal-causing characters such as ctrl-C (interrupt),
  73.  *         etc. are NOT disabled.
  74.  * It doesn't matter whether an input \n is mapped to \r, or vice versa.
  75.  */
  76.     public void
  77. raw_mode(on)
  78.     int on;
  79. {
  80. #ifdef amiga
  81.     extern int do_echo;
  82.  
  83.     if (on)
  84.         do_echo = 0;
  85.     else
  86.         do_echo = 1;
  87.         erase_char = 8; /* ^H */
  88.     kill_char = 24; /* ^X */
  89. #else
  90. #if TERMIO
  91.     struct termio s;
  92.     static struct termio save_term;
  93.  
  94.     if (on)
  95.     {
  96.         /*
  97.          * Get terminal modes.
  98.          */
  99.         ioctl(2, TCGETA, &s);
  100.  
  101.         /*
  102.          * Save modes and set certain variables dependent on modes.
  103.          */
  104.         save_term = s;
  105.         ospeed = s.c_cflag & CBAUD;
  106.         erase_char = s.c_cc[VERASE];
  107.         kill_char = s.c_cc[VKILL];
  108.  
  109.         /*
  110.          * Set the modes to the way we want them.
  111.          */
  112.         s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
  113.         s.c_oflag |=  (OPOST|ONLCR|TAB3);
  114.         s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
  115.         s.c_cc[VMIN] = 1;
  116.         s.c_cc[VTIME] = 0;
  117.     } else
  118.     {
  119.         /*
  120.          * Restore saved modes.
  121.          */
  122.         s = save_term;
  123.     }
  124.     ioctl(2, TCSETAW, &s);
  125. #else
  126.     struct sgttyb s;
  127.     static struct sgttyb save_term;
  128.  
  129.     if (on)
  130.     {
  131.         /*
  132.          * Get terminal modes.
  133.          */
  134.         ioctl(2, TIOCGETP, &s);
  135.  
  136.         /*
  137.          * Save modes and set certain variables dependent on modes.
  138.          */
  139.         save_term = s;
  140.         ospeed = s.sg_ospeed;
  141.         erase_char = s.sg_erase;
  142.         kill_char = s.sg_kill;
  143.  
  144.         /*
  145.          * Set the modes to the way we want them.
  146.          */
  147.         s.sg_flags |= CBREAK;
  148.         s.sg_flags &= ~(ECHO|XTABS);
  149.     } else
  150.     {
  151.         /*
  152.          * Restore saved modes.
  153.          */
  154.         s = save_term;
  155.     }
  156.     ioctl(2, TIOCSETN, &s);
  157. #endif
  158. #endif
  159. }
  160.  
  161. static int couldnt = 0;
  162.  
  163.     static void
  164. cannot(s)
  165.     char *s;
  166. {
  167.     if (know_dumb)
  168.         /* 
  169.          * He knows he has a dumb terminal, so don't tell him. 
  170.          */
  171.         return;
  172.  
  173.     printf("WARNING: terminal cannot \"%s\"\n", s);
  174.     couldnt = 1;
  175. }
  176.  
  177. /*
  178.  * Get terminal capabilities via termcap.
  179.  */
  180.     public void
  181. get_term()
  182. {
  183.     char termbuf[1024];
  184.     char *sp;
  185.     static char sbuf[150];
  186. #ifdef amiga
  187.  
  188.  
  189. /* I didn't want to port termcap for now, but there is a version
  190.  on fish #14 that someone might want to use */
  191.     sc_pad = "";                /* Pad string */
  192.     sc_home = "\x9b1;1H";        /* Cursor home */
  193.     sc_addline = "\x9bL";       /* Add line, scroll down following lines */
  194.     sc_lower_left = "\x9b23;1H";/* Cursor to last line, first column */
  195.     sc_move = "";               /* General cursor positioning */
  196.     sc_clear = "\f";            /* Clear screen */
  197.     sc_eol_clear = "\x9bK";     /* Clear to end of line */
  198.     sc_s_in = "\x9b0;32;43m";   /* Enter standout (highlighted) mode */
  199.     sc_s_out = "\x9bm";         /* Exit standout mode */
  200.     sc_u_in = "\x9b4m";         /* Enter underline mode */
  201.     sc_u_out = "\x9bm";         /* Exit underline mode */
  202.     sc_visual_bell = "\007";    /* Visual bell (flash screen) sequence */
  203.     sc_backspace = "\b";      /* Backspace cursor */
  204.     sc_init = "";               /* Startup terminal initialization */
  205.     sc_deinit = "";             /* Exit terminal de-intialization */
  206.     sc_height = 23;
  207.     sc_width = 77;
  208. #else
  209.     char *getenv();
  210.  
  211.     /*
  212.      * Find out what kind of terminal this is.
  213.      */
  214.     if (tgetent(termbuf, getenv("TERM")) <= 0)
  215.         dumb = 1;
  216.  
  217.     /*
  218.      * Get size of the screen.
  219.      */
  220.     if (dumb || (sc_height = tgetnum("li")) < 0 || tgetflag("hc"))
  221.     {
  222.         /* Oh no, this is a hardcopy terminal. */
  223.         hard = 1;
  224.         sc_height = 24;
  225.     }
  226.     if (dumb || (sc_width = tgetnum("co")) < 0)
  227.         sc_width = 80;
  228.  
  229.     auto_wrap = tgetflag("am");
  230.     ignaw = tgetflag("xn");
  231.  
  232.     /*
  233.      * Assumes termcap variable "sg" is the printing width of
  234.      * the standout sequence, the end standout sequence,
  235.      * the underline sequence, and the end underline sequence.
  236.      */
  237.     if ((ul_width = tgetnum("sg")) < 0)
  238.         ul_width = 0;
  239.     so_width = se_width = ue_width = ul_width;
  240.  
  241.     /*
  242.      * Get various string-valued capabilities.
  243.      */
  244.     sp = sbuf;
  245.  
  246.     sc_pad = (dumb) ? NULL : tgetstr("pc", &sp);
  247.     if (sc_pad != NULL)
  248.         PC = *sc_pad;
  249.  
  250.     sc_init = (dumb) ? NULL : tgetstr("ti", &sp);
  251.     if (sc_init == NULL)
  252.         sc_init = "";
  253.  
  254.     sc_deinit= (dumb) ? NULL : tgetstr("te", &sp);
  255.     if (sc_deinit == NULL)
  256.         sc_deinit = "";
  257.  
  258.     sc_eol_clear = (dumb) ? NULL : tgetstr("ce", &sp);
  259.     if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0')
  260.     {
  261.         cannot("clear to end of line");
  262.         sc_eol_clear = "";
  263.     }
  264.  
  265.     sc_clear = (dumb) ? NULL : tgetstr("cl", &sp);
  266.     if (hard || sc_clear == NULL || *sc_clear == '\0')
  267.     {
  268.         cannot("clear screen");
  269.         sc_clear = "\n\n";
  270.     }
  271.  
  272.     sc_move = (dumb) ? NULL : tgetstr("cm", &sp);
  273.     if (hard || sc_move == NULL || *sc_move == '\0')
  274.     {
  275.         /*
  276.          * This is not an error here, because we don't 
  277.          * always need sc_move.
  278.          * We need it only if we don't have home or lower-left.
  279.          */
  280.         sc_move = "";
  281.     }
  282.  
  283.     sc_s_in = (dumb) ? NULL : tgetstr("so", &sp);
  284.     if (hard || sc_s_in == NULL)
  285.         sc_s_in = "";
  286.  
  287.     sc_s_out = (dumb) ? NULL : tgetstr("se", &sp);
  288.     if (hard || sc_s_out == NULL)
  289.         sc_s_out = "";
  290.  
  291.     sc_u_in = (dumb) ? NULL : tgetstr("us", &sp);
  292.     if (hard || sc_u_in == NULL)
  293.         sc_u_in = sc_s_in;
  294.  
  295.     sc_u_out = (dumb) ? NULL : tgetstr("ue", &sp);
  296.     if (hard || sc_u_out == NULL)
  297.         sc_u_out = sc_s_out;
  298.  
  299.     sc_visual_bell = (dumb) ? NULL : tgetstr("vb", &sp);
  300.     if (hard || sc_visual_bell == NULL)
  301.         sc_visual_bell = "";
  302.  
  303.     sc_home = (dumb) ? NULL : tgetstr("ho", &sp);
  304.     if (hard || sc_home == NULL || *sc_home == '\0')
  305.     {
  306.         if (*sc_move == '\0')
  307.         {
  308.             cannot("home cursor");
  309.             /*
  310.              * This last resort for sc_home is supposed to
  311.              * be an up-arrow suggesting moving to the 
  312.              * top of the "virtual screen". (The one in
  313.              * your imagination as you try to use this on
  314.              * a hard copy terminal.)
  315.              */
  316.             sc_home = "|\b^";               
  317.         } else
  318.         {
  319.             /* 
  320.              * No "home" string,
  321.              * but we can use "move(0,0)".
  322.              */
  323.             strcpy(sp, tgoto(sc_move, 0, 0));
  324.             sc_home = sp;
  325.             sp += strlen(sp) + 1;
  326.         }
  327.     }
  328.  
  329.     sc_lower_left = (dumb) ? NULL : tgetstr("ll", &sp);
  330.     if (hard || sc_lower_left == NULL || *sc_lower_left == '\0')
  331.     {
  332.         if (*sc_move == '\0')
  333.         {
  334.             cannot("move cursor to lower left of screen");
  335.             sc_lower_left = "\r";
  336.         } else
  337.         {
  338.             /*
  339.              * No "lower-left" string, 
  340.              * but we can use "move(0,last-line)".
  341.              */
  342.             strcpy(sp, tgoto(sc_move, 0, sc_height-1));
  343.             sc_lower_left = sp;
  344.             sp += strlen(sp) + 1;
  345.         }
  346.     }
  347.  
  348.     /*
  349.      * To add a line at top of screen and scroll the display down,
  350.      * we use "al" (add line) or "sr" (scroll reverse).
  351.      */
  352.     if (dumb)
  353.         sc_addline = NULL;
  354.     else if ((sc_addline = tgetstr("al", &sp)) == NULL || 
  355.          *sc_addline == '\0')
  356.         sc_addline = tgetstr("sr", &sp);
  357.  
  358.     if (hard || sc_addline == NULL || *sc_addline == '\0')
  359.     {
  360.         cannot("scroll backwards");
  361.         sc_addline = "";
  362.         /* Force repaint on any backward movement */
  363.         back_scroll = 0;
  364.     }
  365.  
  366.     if (dumb || tgetflag("bs"))
  367.         sc_backspace = "\b";
  368.     else
  369.     {
  370.         sc_backspace = tgetstr("bc", &sp);
  371.         if (sc_backspace == NULL || *sc_backspace == '\0')
  372.             sc_backspace = "\b";
  373.     }
  374.  
  375.     if (couldnt)
  376.         /* Give him time to read all the "cannot" messages. */
  377.         error("");
  378. #endif
  379. }
  380.  
  381.  
  382. /*
  383.  * Below are the functions which perform all the 
  384.  * terminal-specific screen manipulation.
  385.  */
  386.  
  387.  
  388. /*
  389.  * Initialize terminal
  390.  */
  391.     public void
  392. init()
  393. {
  394.     tputs(sc_init, sc_height, putc);
  395. }
  396.  
  397. /*
  398.  * Deinitialize terminal
  399.  */
  400.     public void
  401. deinit()
  402. {
  403.     tputs(sc_deinit, sc_height, putc);
  404. }
  405.  
  406. /*
  407.  * Home cursor (move to upper left corner of screen).
  408.  */
  409.     public void
  410. home()
  411. {
  412.     tputs(sc_home, 1, putc);
  413. }
  414.  
  415. /*
  416.  * Add a blank line (called with cursor at home).
  417.  * Should scroll the display down.
  418.  */
  419.     public void
  420. add_line()
  421. {
  422.     tputs(sc_addline, sc_height, putc);
  423. }
  424.  
  425. /*
  426.  * Move cursor to lower left corner of screen.
  427.  */
  428.     public void
  429. lower_left()
  430. {
  431.     tputs(sc_lower_left, 1, putc);
  432. }
  433.  
  434. /*
  435.  * Ring the terminal bell.
  436.  */
  437.     public void
  438. bell()
  439. {
  440.     if (quiet == VERY_QUIET)
  441.         vbell();
  442.     else
  443.         putc('\7');
  444. }
  445.  
  446. /*
  447.  * Output the "visual bell", if there is one.
  448.  */
  449.     public void
  450. vbell()
  451. {
  452.     if (*sc_visual_bell == '\0')
  453.         return;
  454.     tputs(sc_visual_bell, sc_height, putc);
  455. }
  456.  
  457. /*
  458.  * Clear the screen.
  459.  */
  460.     public void
  461. clear()
  462. {
  463.     tputs(sc_clear, sc_height, putc);
  464. }
  465.  
  466. /*
  467.  * Clear from the cursor to the end of the cursor's line.
  468.  * {{ This must not move the cursor. }}
  469.  */
  470.     public void
  471. clear_eol()
  472. {
  473.     tputs(sc_eol_clear, 1, putc);
  474. }
  475.  
  476. /*
  477.  * Begin "standout" (bold, underline, or whatever).
  478.  */
  479.     public void
  480. so_enter()
  481. {
  482.     tputs(sc_s_in, 1, putc);
  483. }
  484.  
  485. /*
  486.  * End "standout".
  487.  */
  488.     public void
  489. so_exit()
  490. {
  491.     tputs(sc_s_out, 1, putc);
  492. }
  493.  
  494. /*
  495.  * Begin "underline" (hopefully real underlining, 
  496.  * otherwise whatever the terminal provides).
  497.  */
  498.     public void
  499. ul_enter()
  500. {
  501.     tputs(sc_u_in, 1, putc);
  502. }
  503.  
  504. /*
  505.  * End "underline".
  506.  */
  507.     public void
  508. ul_exit()
  509. {
  510.     tputs(sc_u_out, 1, putc);
  511. }
  512.  
  513. /*
  514.  * Erase the character to the left of the cursor 
  515.  * and move the cursor left.
  516.  */
  517.     public void
  518. backspace()
  519. {
  520.     /* 
  521.      * Try to erase the previous character by overstriking with a space.
  522.      */
  523.     tputs(sc_backspace, 1, putc);
  524.     putc(' ');
  525.     tputs(sc_backspace, 1, putc);
  526. }
  527.  
  528. /*
  529.  * Output a plain backspace, without erasing the previous char.
  530.  */
  531.     public void
  532. putbs()
  533. {
  534.     tputs(sc_backspace, 1, putc);
  535. }
  536.